package com.example.rustfs.service;

import com.example.rustfs.config.RustFsConfig;
import com.example.rustfs.dto.FileInfo;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import software.amazon.awssdk.core.ResponseInputStream;
import software.amazon.awssdk.core.sync.RequestBody;
import software.amazon.awssdk.services.s3.S3Client;
import software.amazon.awssdk.services.s3.model.*;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.List;

/**
 * 文件服务类
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class FileService {

    private final S3Client s3Client;
    private final RustFsConfig rustFsConfig;

    /**
     * 初始化存储桶
     */
    public void initBucket() {
        try {
            // 检查存储桶是否存在
            HeadBucketRequest headBucketRequest = HeadBucketRequest.builder()
                    .bucket(rustFsConfig.getBucketName())
                    .build();
            
            try {
                s3Client.headBucket(headBucketRequest);
                log.info("存储桶 {} 已存在", rustFsConfig.getBucketName());
            } catch (NoSuchBucketException e) {
                // 创建存储桶
                CreateBucketRequest createBucketRequest = CreateBucketRequest.builder()
                        .bucket(rustFsConfig.getBucketName())
                        .build();
                s3Client.createBucket(createBucketRequest);
                log.info("存储桶 {} 创建成功", rustFsConfig.getBucketName());
            }
        } catch (Exception e) {
            log.error("初始化存储桶失败", e);
        }
    }

    /**
     * 列出文件和文件夹
     */
    public List<FileInfo> listFiles(String prefix) {
        return listFiles(prefix, null);
    }
    
    /**
     * 列出文件和文件夹（支持文件类型筛选）
     * @param prefix 路径前缀
     * @param fileType 文件类型过滤：image, document, video, audio, null表示所有
     */
    public List<FileInfo> listFiles(String prefix, String fileType) {
        List<FileInfo> fileInfoList = new ArrayList<>();
        
        if (prefix == null) {
            prefix = "";
        }
        
        // 确保前缀以斜杠结尾（如果不为空）
        if (!prefix.isEmpty() && !prefix.endsWith("/")) {
            prefix += "/";
        }

        try {
            ListObjectsV2Request listRequest = ListObjectsV2Request.builder()
                    .bucket(rustFsConfig.getBucketName())
                    .prefix(prefix)
                    .delimiter("/")
                    .build();

            ListObjectsV2Response listResponse = s3Client.listObjectsV2(listRequest);

            // 处理文件夹（公共前缀）
            if (fileType == null) {  // 只在查看所有文件时显示文件夹
                for (CommonPrefix commonPrefix : listResponse.commonPrefixes()) {
                    String folderKey = commonPrefix.prefix();
                    String folderName = folderKey.substring(prefix.length());
                    if (!folderName.isEmpty()) {
                        folderName = folderName.replaceAll("/$", "");
                        FileInfo fileInfo = new FileInfo();
                        fileInfo.setName(folderName);
                        fileInfo.setKey(folderKey);
                        fileInfo.setType("folder");
                        fileInfo.setIcon("bi-folder-fill");
                        fileInfo.setFormattedSize("-");
                        fileInfoList.add(fileInfo);
                    }
                }
            }

            // 处理文件
            for (S3Object s3Object : listResponse.contents()) {
                String key = s3Object.key();
                // 跳过当前目录本身
                if (key.equals(prefix)) {
                    continue;
                }
                
                String fileName = key.substring(prefix.length());
                
                // 文件类型过滤
                if (fileType != null && !matchFileType(fileName, fileType)) {
                    continue;
                }
                
                FileInfo fileInfo = new FileInfo();
                fileInfo.setName(fileName);
                fileInfo.setKey(key);
                fileInfo.setSize(s3Object.size());
                fileInfo.setLastModified(s3Object.lastModified());
                fileInfo.setType("file");
                fileInfo.setIcon(getFileIcon(fileName));
                fileInfo.setFormattedSize(formatFileSize(s3Object.size()));
                fileInfoList.add(fileInfo);
            }

        } catch (Exception e) {
            log.error("列出文件失败: {}", e.getMessage(), e);
        }

        return fileInfoList;
    }
    
    /**
     * 列出所有文件（递归，用于文件类型筛选）
     */
    public List<FileInfo> listAllFilesByType(String fileType) {
        List<FileInfo> fileInfoList = new ArrayList<>();
        
        try {
            ListObjectsV2Request listRequest = ListObjectsV2Request.builder()
                    .bucket(rustFsConfig.getBucketName())
                    .build();

            ListObjectsV2Response listResponse = s3Client.listObjectsV2(listRequest);

            // 处理所有文件
            for (S3Object s3Object : listResponse.contents()) {
                String key = s3Object.key();
                
                // 跳过文件夹标记
                if (key.endsWith("/")) {
                    continue;
                }
                
                String fileName = key.contains("/") ? key.substring(key.lastIndexOf("/") + 1) : key;
                
                // 文件类型过滤
                if (fileType != null && !matchFileType(fileName, fileType)) {
                    continue;
                }
                
                FileInfo fileInfo = new FileInfo();
                fileInfo.setName(fileName);
                fileInfo.setKey(key);
                fileInfo.setSize(s3Object.size());
                fileInfo.setLastModified(s3Object.lastModified());
                fileInfo.setType("file");
                fileInfo.setIcon(getFileIcon(fileName));
                fileInfo.setFormattedSize(formatFileSize(s3Object.size()));
                fileInfoList.add(fileInfo);
            }

        } catch (Exception e) {
            log.error("列出所有文件失败: {}", e.getMessage(), e);
        }

        return fileInfoList;
    }
    
    /**
     * 判断文件是否匹配指定类型
     */
    private boolean matchFileType(String fileName, String fileType) {
        String ext = getFileExtension(fileName).toLowerCase();
        
        return switch (fileType) {
            case "image" -> ext.matches("jpg|jpeg|png|gif|bmp|svg|webp|ico");
            case "document" -> ext.matches("doc|docx|xls|xlsx|ppt|pptx|pdf|txt|md|csv");
            case "video" -> ext.matches("mp4|avi|mov|wmv|flv|mkv|webm|m4v|ogv");
            case "audio" -> ext.matches("mp3|wav|flac|aac|ogg|oga|m4a|wma|opus");
            default -> true;
        };
    }
    
    /**
     * 获取文件扩展名
     */
    private String getFileExtension(String fileName) {
        if (fileName == null || !fileName.contains(".")) {
            return "";
        }
        return fileName.substring(fileName.lastIndexOf(".") + 1);
    }

    /**
     * 上传文件
     */
    public void uploadFile(MultipartFile file, String path, Long userId) throws IOException {
        String key = path;
        if (!path.isEmpty() && !path.endsWith("/")) {
            key = path + "/";
        }
        key += file.getOriginalFilename();

        PutObjectRequest putRequest = PutObjectRequest.builder()
                .bucket(rustFsConfig.getBucketName())
                .key(key)
                .contentType(file.getContentType())
                .build();

        s3Client.putObject(putRequest, RequestBody.fromInputStream(file.getInputStream(), file.getSize()));
        log.info("文件上传成功: {}", key);
    }
    
    /**
     * 计算用户存储空间使用量
     */
    public long calculateUserStorageUsed(Long userId) {
        long totalSize = 0;
        try {
            ListObjectsV2Request listRequest = ListObjectsV2Request.builder()
                    .bucket(rustFsConfig.getBucketName())
                    .build();

            ListObjectsV2Response listResponse = s3Client.listObjectsV2(listRequest);

            for (S3Object s3Object : listResponse.contents()) {
                String key = s3Object.key();
                // 排除回收站文件
                if (!key.startsWith(".recycle/")) {
                    totalSize += s3Object.size();
                }
            }
        } catch (Exception e) {
            log.error("计算存储空间失败", e);
        }
        return totalSize;
    }

    /**
     * 下载文件
     */
    public byte[] downloadFile(String key) throws IOException {
        GetObjectRequest getRequest = GetObjectRequest.builder()
                .bucket(rustFsConfig.getBucketName())
                .key(key)
                .build();

        ResponseInputStream<GetObjectResponse> response = s3Client.getObject(getRequest);
        return readAllBytes(response);
    }

    /**
     * 删除文件
     */
    public void deleteFile(String key) {
        DeleteObjectRequest deleteRequest = DeleteObjectRequest.builder()
                .bucket(rustFsConfig.getBucketName())
                .key(key)
                .build();

        s3Client.deleteObject(deleteRequest);
        log.info("文件删除成功: {}", key);
    }

    /**
     * 删除文件夹（递归删除）
     */
    public void deleteFolder(String prefix) {
        if (!prefix.endsWith("/")) {
            prefix += "/";
        }

        // 列出文件夹下所有对象
        ListObjectsV2Request listRequest = ListObjectsV2Request.builder()
                .bucket(rustFsConfig.getBucketName())
                .prefix(prefix)
                .build();

        ListObjectsV2Response listResponse = s3Client.listObjectsV2(listRequest);

        // 删除所有对象
        for (S3Object s3Object : listResponse.contents()) {
            deleteFile(s3Object.key());
        }

        log.info("文件夹删除成功: {}", prefix);
    }

    /**
     * 创建文件夹
     */
    public void createFolder(String path, String folderName) {
        String key = path;
        if (!path.isEmpty() && !path.endsWith("/")) {
            key = path + "/";
        }
        key += folderName + "/";

        PutObjectRequest putRequest = PutObjectRequest.builder()
                .bucket(rustFsConfig.getBucketName())
                .key(key)
                .build();

        s3Client.putObject(putRequest, RequestBody.fromBytes(new byte[0]));
        log.info("文件夹创建成功: {}", key);
    }

    /**
     * 重命名文件或文件夹
     */
    public void rename(String oldKey, String newName) {
        // 判断是否为文件夹
        boolean isFolder = oldKey.endsWith("/");
        
        // 构建新的 key
        String parentPath = oldKey.substring(0, oldKey.lastIndexOf("/") + 1);
        String newKey = parentPath + newName;
        if (isFolder) {
            newKey += "/";
        }

        if (isFolder) {
            // 重命名文件夹需要递归处理
            renameFolder(oldKey, newKey);
        } else {
            // 重命名文件
            copyObject(oldKey, newKey);
            deleteFile(oldKey);
        }

        log.info("重命名成功: {} -> {}", oldKey, newKey);
    }

    /**
     * 重命名文件夹（递归）
     */
    private void renameFolder(String oldPrefix, String newPrefix) {
        ListObjectsV2Request listRequest = ListObjectsV2Request.builder()
                .bucket(rustFsConfig.getBucketName())
                .prefix(oldPrefix)
                .build();

        ListObjectsV2Response listResponse = s3Client.listObjectsV2(listRequest);

        for (S3Object s3Object : listResponse.contents()) {
            String oldKey = s3Object.key();
            String newKey = oldKey.replaceFirst("^" + oldPrefix, newPrefix);
            copyObject(oldKey, newKey);
            deleteFile(oldKey);
        }
    }

    /**
     * 复制对象
     */
    private void copyObject(String sourceKey, String destKey) {
        CopyObjectRequest copyRequest = CopyObjectRequest.builder()
                .sourceBucket(rustFsConfig.getBucketName())
                .sourceKey(sourceKey)
                .destinationBucket(rustFsConfig.getBucketName())
                .destinationKey(destKey)
                .build();

        s3Client.copyObject(copyRequest);
    }

    /**
     * 获取文件图标
     */
    private String getFileIcon(String fileName) {
        String ext = fileName.substring(fileName.lastIndexOf(".") + 1).toLowerCase();
        return switch (ext) {
            case "pdf" -> "bi-file-earmark-pdf-fill";
            case "doc", "docx" -> "bi-file-earmark-word-fill";
            case "xls", "xlsx" -> "bi-file-earmark-excel-fill";
            case "ppt", "pptx" -> "bi-file-earmark-ppt-fill";
            case "jpg", "jpeg", "png", "gif", "bmp", "webp", "svg" -> "bi-file-earmark-image-fill";
            case "zip", "rar", "7z", "tar", "gz" -> "bi-file-earmark-zip-fill";
            case "txt", "md" -> "bi-file-earmark-text-fill";
            case "mp4", "avi", "mov", "wmv", "flv", "mkv", "webm", "ogv" -> "bi-file-earmark-play-fill";
            case "mp3", "wav", "flac", "aac", "ogg", "oga", "m4a", "wma", "opus" -> "bi-file-earmark-music-fill";
            case "java", "js", "py", "cpp", "c", "html", "css", "json", "xml" -> "bi-file-earmark-code-fill";
            default -> "bi-file-earmark-fill";
        };
    }

    /**
     * 格式化文件大小
     */
    private String formatFileSize(long size) {
        if (size <= 0) return "0 B";
        final String[] units = new String[]{"B", "KB", "MB", "GB", "TB"};
        int digitGroups = (int) (Math.log10(size) / Math.log10(1024));
        return new DecimalFormat("#,##0.##").format(size / Math.pow(1024, digitGroups)) + " " + units[digitGroups];
    }

    /**
     * 读取输入流全部字节
     */
    private byte[] readAllBytes(InputStream inputStream) throws IOException {
        ByteArrayOutputStream buffer = new ByteArrayOutputStream();
        int nRead;
        byte[] data = new byte[16384];
        while ((nRead = inputStream.read(data, 0, data.length)) != -1) {
            buffer.write(data, 0, nRead);
        }
        return buffer.toByteArray();
    }
}

